class Characteristic
{
	constructor(conn, devid, serid)
	{
		this.conn = conn;
		this.devid = devid;
		this.serid = serid + "";
	}

	zero(str, len)
	{
		var zero = "00000000";
		zero = zero + str;
		return zero.substring(zero.length - 2);
	}

	checkCRC(str)
	{
		var bCheck = 0;
		for (var i = 0; i < str.length; i++)
		{
			bCheck = bCheck ^ str.charCodeAt(i);
		}
		return this.zero(bCheck.toString(16), 2);
	}

	writeCha(devid, serid, cha, ord)
	{
		var buf = new ArrayBuffer(ord.length);
		var bufView = new Uint8Array(buf);
		for (var i = 0; i < ord.length; i++)
		{
			bufView[i] = ord.charCodeAt(i);
		}
		console.log("buffer:", bufView[0], bufView[1], bufView[2], bufView[11], bufView[12], bufView[13], bufView[14], bufView[15]);
		console.log("writecha:", this.conn.writecha);

		wx.writeBLECharacteristicValue(
		{
			deviceId: devid,
			serviceId: serid,
			characteristicId: cha,
			value: bufView.buffer,
			success: res =>
			{
				// success
				console.log("success  first 指令发送成功:", cha);
				console.log(res);
			},
			fail: function (res)
			{
				// fail
				console.log("write failed:", res);
			},
			complete: function (res)
			{
				// complete
			}
		})
	}

	Doit()
	{
		wx.getBLEDeviceCharacteristics(
		{
			// 这里的 deviceId 需要在上面的 getBluetoothDevices
			deviceId: this.devid,
			// 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
			serviceId: this.serid,
			success: cha =>
			{
				for (var j = 0; j < cha.characteristics.length; j++)
				{
					if (cha.characteristics[j].properties.notify)
					{
						console.log("bind notify", cha.characteristics[j])
						this.conn.notifycha = cha.characteristics[j].uuid + "";
						this.conn.notifyser = this.serid;

						wx.onBLECharacteristicValueChange(ch =>
						{
							console.log('characteristic value comed:', ch.value);

							var reqCMD = String.fromCharCode.apply(null, new Uint8Array(ch.value));
							console.log('recv:', reqCMD);
							if (reqCMD.indexOf("@03") >= 0)
							{
								this.conn.ConnectSucc();
								this.conn.opendoor.callback({ code: 200, info: "开门成功", title: "", content: "" });
								console.log("回复退出." + reqCMD);
							} else if (reqCMD.indexOf("@ER") >= 0)
							{
								this.conn.opendoor.callback({ code: 503, info: "开门失败", title: "", content: "" });
								console.log("回复错误." + reqCMD);
							} else if (reqCMD.indexOf("@04") >= 0)
							{
								var open_key = this.conn.openkey;
								var TID = open_key.substring(3, 11);
								var KEY = reqCMD.substring(5, 9);
								var sKey = parseInt(KEY, 16);
								var sNum = sKey % 16;

								sKey = ((sKey << sNum) | (sKey >> (16 - sNum)));
								var KEYS = new Uint8Array(2);
								KEYS[0] = sKey / 256;
								KEYS[1] = sKey % 256;
								var TIDS = new Uint8Array(4);
								TIDS[0] = parseInt(TID.substring(0, 2), 16);
								TIDS[1] = parseInt(TID.substring(2, 4), 16);
								TIDS[2] = parseInt(TID.substring(4, 6), 16);
								TIDS[3] = parseInt(TID.substring(6, 8), 16);
								for (var i = 0; i < 4; i++)
								{
									TIDS[i] = TIDS[i] ^ KEYS[i % 2];
								}
								var mCmd = open_key.replace(TID, this.zero(TIDS[0].toString(16), 2) + this.zero(TIDS[1].toString(16), 2) + this.zero(TIDS[2].toString(16), 2) + this.zero(TIDS[3].toString(16), 2));
								mCmd = mCmd.substring(0, mCmd.length - 3) + this.checkCRC(mCmd.substring(1, mCmd.length - 3)) + "*";
								console.log("发出开门指令." + mCmd);
								this.writeCha(this.conn.devid, this.conn.writeser, this.conn.writecha, mCmd);
							}
						})
                        /**
                         * 顺序开发设备特征notifiy
                         */
						wx.notifyBLECharacteristicValueChanged({
							deviceId: this.devid,
							serviceId: this.serid,
							characteristicId: this.conn.notifycha,
							state: true,
							success: function (res)
							{
								// success
								console.log('notifyBLECharacteristicValueChanged success', res);
							},
							fail: function (res)
							{
								// fail
								console.log('notifyBLECharacteristicValueChanged fail', res);
							},
							complete: function (res)
							{
								// complete
							}
						})
					}

					if (cha.characteristics[j].properties.write)
					{
						console.log("bind write", cha.characteristics[j])
						if (this.conn.writeser=="")
						{
							this.conn.writecha = cha.characteristics[j].uuid + "";
							this.conn.writeser = this.serid;

							var ord = "@04000000001603*";
							this.writeCha(this.conn.devid, this.conn.writeser, this.conn.writecha, ord);
						}
					}
				}
			},
			fail: function (res)
			{
				console.log(res);
			}
		})
	}
}

class Connection
{
	constructor(opendoor,devid,openkey)
	{
		this.devid = devid;
		this.notifycha = "";
		this.writecha = "";
		this.notifyser = "";
		this.writeser = "";
		this.opendoor = opendoor;
		this.openkey = openkey;

		this.opensuccess = false;
	}

	ConnectSucc()
	{
		this.opensuccess = true;

		wx.closeBLEConnection(
		{
			deviceId: this.devid,
			success: function(res) {},
			complete: res=>
			{
				wx.stopBluetoothDevicesDiscovery(
				{
					success: function(res) {},
					complete: res=>
					{
						wx.closeBluetoothAdapter({
							success: function(res) {},
							complete: res =>
							{
								this.opendoor.once = true;
							}
						})
					}
				})
			}
		})
	}

	Connect()
	{
		wx.onBLEConnectionStateChanged(res =>
		{
			console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`);
			var status = "";
			if ( res.connected )
				this.opendoor.callback({ code: 150, info: "连接成功", title: "", content: "" });
			else
				this.opendoor.callback({ code: 504, info: "连接中断", title: "", content: "" });
		})

		var ctrytimes = 0;
		this.opensuccess = false;

		var createConnection = function ()
		{
			// wx.closeBLEConnection({
			// 	deviceId: this.devid,
			// 	success: function(res) {},
			// 	complete: res =>
			// 	{
					if ( !this.opensuccess && ctrytimes < this.opendoor.times)
					{
						ctrytimes ++;

						console.log("try...........................",ctrytimes);

						wx.createBLEConnection(
						{
							deviceId: this.devid,
							success: res =>
							{
								this.opendoor.callback({ code: 102, info: "连接设备成功", title: "", content: "" });
								console.log("连接设备成功", res)

								setTimeout( function()
								{
									wx.getBLEDeviceServices(
									{
										// 这里的 deviceId 需要在上面的 getBluetoothDevices中获取
										deviceId: this.devid,
										success: service =>
										{
											console.log('device services:', service.services)
											for (var i = 0; i < service.services.length; i++)
											{
												var gc = new Characteristic(this, this.devid, service.services[i].uuid);
												gc.Doit();
											}
										},
										fail: function (res)
										{
											// fail
											console.log('getser failed:', res)
										},
										complete: function (res)
										{
											// complete
										}
									})
								}.bind(this), 10)
							},
							fail: res=>
							{
								this.opendoor.callback({ code: 502, info: "连接设备失败", title: "", content: "" });
								console.log(res)
							}
						})

						setTimeout(createConnection.bind(this), this.opendoor.timeout);
					}

					if (this.opensuccess || ctrytimes >= this.opendoor.times)
						wx.stopBluetoothDevicesDiscovery(
						{
							success: function (res) { },
							complete: res=>
							{
								wx.closeBluetoothAdapter(
								{
									success: function (res) { },
									complete: res=>
									{
										this.opendoor.once = true;
									}
								})
							}
						})
			// 	}
			// })
		}

		var cc = createConnection.bind(this);
		cc();
	}
}

class OpenDoor
{
	constructor()
	{
		this.successopen = false;
		this.finddev = false;
		this.isbluetoothready = false;
		this.searchingstatus = false;

		this.onBLEStateChange = false;
		this.onBLEDeviceFound = false;
		this.once = true;
	}

	StopScan(devid,openkey)
	{
		wx.stopBluetoothDevicesDiscovery({
			success: res =>
			{
				console.log("成功停止搜索:", res)
			},
			complete: res =>
			{
				var conn = new Connection(this, devid, openkey);
				setTimeout(function ()
				{
					console.log("开始连接蓝牙:", res)
					conn.Connect();
				}.bind(this), 10)
			}
		})
	}

	Open(timeout, times, egklist, callback)
	{
		if ( this.once )
		{
			this.timeout = timeout;
			this.times = times;
			this.egklist = egklist;
			this.callback = callback;
			this.scan_period = (timeout + 666) * (times + 1) + 4333;

			this.finddev = false;
			this.once = false;
			this.finddev = false;

			var ctime = new Date();
			this.ctime = ctime;

			wx.openBluetoothAdapter(
			{
				success: res =>
				{
					this.callback({ code: 100, info: "初始化蓝牙成功", title: "", content: "" });

					if (!this.onBLEStateChange)
					{
						this.onBLEStateChange = true;

						wx.onBluetoothAdapterStateChange(res =>
						{
							console.log("蓝牙适配器状态变化", res);
							this.isbluetoothready = res.available;
							this.searchingstatus = res.discovering;
						})
					}

					if (!this.onBLEDeviceFound)
					{
						this.onBLEDeviceFound = true;

						wx.onBluetoothDeviceFound(devices =>
						{
							console.log('发现新蓝牙设备', devices);

							var max_rssi=-1;
							var max_device_id="";
							var max_key="";

							for (var i = 0; i < devices.devices.length; i++)
							{
								console.log(devices.devices[i])
								console.log('设备id' + devices.devices[i].deviceId)
								console.log('设备name' + devices.devices[i].name)

								for (var j = 0; j < this.egklist.length; j++)
									if (this.egklist[j].name == devices.devices[i].name)
									{
										if ( !this.finddev)
										{
											this.finddev = true;
											max_rssi = devices.devices[i].RSSI;
											max_device_id = devices.devices[i].deviceId;
											max_key = this.egklist[j].key;
										}else if ( devices.devices[i].RSSI > max_rssi )
										{
											max_rssi = devices.devices[i].RSSI;
											max_device_id = devices.devices[i].deviceId;
											max_key = this.egklist[j].key;
										}
									}
							}
							if (this.finddev)
							{
								this.callback({ code: 101, info: "发现合法蓝牙", title: "", content: "" });
								this.StopScan(max_device_id, max_key)
							}
						})
					}

					wx.startBluetoothDevicesDiscovery(
						{
							success: res =>
							{
								console.log("开始搜索附近蓝牙设备")
								console.log(res)
							}
						})
				},
				fail: res =>
				{
					this.callback({ code: 501, info: "初始化蓝牙失败", title: "提示", content: "请检查手机蓝牙是否打开" });
					this.isbluetoothready = false;
					this.searchingstatus = false;
				}
			})

			setTimeout( function()
			{
				if ( !this.once && this.ctime == ctime )
				{
					wx.stopBluetoothDevicesDiscovery(
					{
						success: function(res) {},
						complete: function(res)
						{
							wx.closeBluetoothAdapter(
							{
								success: function(res) {},
							})
						}
					})

					if ( !this.finddev )
						this.callback({ code: 505, info: "未发现合法蓝牙", title: "", content: "" });

					this.once = true;
				}
			}.bind(this), this.scan_period );
		}else
			this.callback({ code: 500, info: "开门进行中...", title: "", content: "" });
	}
}

const g_opendoor = new OpenDoor()

export { g_opendoor};